前面講了很久MTV不同的功能,其實用到的都還是我們一開始在View裡面提到的Function Based View。
為什麼會等到現在才講 Class Based View呢?
因為裡面會牽扯到Template和Model 所以我想要在講完Template和Model之後
再帶到Class Based View
在講之前我們要先來回顧一下什麼是CBVs(Class Based Views),以及為什麼要去使用他
我們原本使用的FBVs(Function Based Views)就已經很直觀很好用了怎麼還要使用CBV呢?
相較於FBVs:
from django.http import HttpResponse
def my_view(request):
if request.method == 'GET':
# <view logic>
return HttpResponse('result')
from django.http import HttpResponse
from django.views import View
class MyView(View):
def get(self, request):
# <view logic>
return HttpResponse('result')
不僅如此Django還內建許多好用的基本類別:
以最基本的 TemplateView 為例,它的用途就是將自定義的模板(Template)呈現出來,並且可以包含Model的查找
原本 render html 的方式,我們可以繼承 TemplateView 的類別
並利用覆寫(overriding)來將它改成我們要使用的模板。
from django.shortcuts import render
from django.http import HttpResponse
from django.views.generic import TemplateView
#FBVs的方法
def home(request):
return render(request, "home.html")
#CBVs的方法
class home_view(TemplateView):
template_name = 'home.html'
我們要先把 class import進來
在urls裡面,因為home不再是函式,所以在建立path時,需要讓class去使用as_view的方法
as_view會調用dispatch的方法,dispatch會去查找是否有這個views的class,如果有就會去呼叫他,並回傳對應的 view,因此在CBVs 若要呼叫view,需要使用as_view。
from .views import home_view
from . import views
urlpatterns = [
#FBVs的方法
path('', views.home, name = "home" ),
#CBVs的方法
path('', home_view.as_view(), name = "home"),
]
CreateView 的功能就是能夠快速的用 Model 建立 Form,不用額外再建立ModelForm。
用法很簡單,首先先建立Model
from unittest.util import _MAX_LENGTH
from django.db import models
# Create your models here.
class account_info(models.Model):
account_name = models.CharField(max_length= 10)
account_email = models.EmailField()
account_order = models.DateField()
再來到 views.py 建立 CreateView
如果你沒有特別設置 template_name的話,他就會自動去找 model名稱_form
的html檔案
你也可以自己設定 tempalte_name 的路徑
fields 也是,用__all__ 的話就是所有欄位都會顯示
也可以用 list 來呈現自己決定要設定的欄位
from django.views.generic import TemplateView, CreateView
from .models import account_info
from django.urls import reverse, reverse_lazy
# Create your views here.
class OrderCreateView(CreateView):
#account_form.html 預設會去找這個html
#template_name = "" 也可以自己定義
model = account_info
#fields = ["account_name"] :決定要設定的欄位
fields = "__all__"
success_url = reverse_lazy("Order_System:finish")
class FinishView(TemplateView):
template_name = "Django_app/finish.html"
我沒有設置 template_name 所以創立了一個 account_info_form.html
可以直接呼叫{{form}}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form method="POST">
{% csrf_token %}
{{form.as_p}}
<input type = "submit" value = "預約">
</form>
</body>
</html>
接著設置好 urls 就可以了。
from django.contrib import admin
from django.urls import path, include
from .views import OrderCreateView, FinishView
app_name = 'Order_System'
urlpatterns = [
path('', OrderCreateView.as_view() , name = 'Odrer'),
path('finish/', FinishView.as_view() , name = 'finish'),
]
我們可以直接打開畫面並填入表單
完成之後就會跳轉到我們設置的 finish
我們就可以到後台看到我們剛剛提交的表單資料
ListView 是用來呈現資料列表的,我們可以用剛剛建立的資料來示範。
首先一樣在views裡建立一個 ListView
接著一樣設定我們的Model
一樣的是如果沒有特別設定template_name, 則Django會自動去找 model名稱_list
設定 queryset 可以對資料進行邏輯的操作,操作方式和我們之前在 model 裡面操作一樣。
context_object_name 可以設定我們在html接收參數時的名稱,若沒有設定則會自動設定成 object_list
class OrderListView(ListView):
# account_info_list.html
# context_object_name = Order_list
model = account_info
# queryset = account_info.objects.all()
設定 urls
from django.urls import path
from .views import OrderCreateView, FinishView, OrderListView
app_name = 'Order_System'
urlpatterns = [
path('', OrderCreateView.as_view() , name = 'Odrer'),
path('finish/', FinishView.as_view() , name = 'finish'),
path('orderlist/', OrderListView.as_view(), name = 'order_list'),
]
因為我們沒有設定 context_object_name 所以我們用 object_list 來進行呼叫。
並將預約人的姓名和預約的時間調出來
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<h1>預約資料表</h1>
<body>
<form method="POST">
{% for data in object_list %}
<li>預約人姓名:{{data.account_name}} 預約時間 {{data.account_order}} </li>
{% endfor %}
</form>
</body>
</html>
和 ListView 類似, DetailView 可以更詳細的呈現單一筆資料
可以用:
首先我們將 models.py 的account_name 裡加上primary_key = True 的屬性,這裡的用途是讓填寫的account_name做為table的主鍵,修改完後記得要migrate
from django.db import models
from datetime import datetime
# Create your models here.
class account_info(models.Model):
account_name = models.CharField(max_length= 10,primary_key=True)
account_email = models.EmailField()
account_order = models.DateField(default = datetime.now())
views 裡面直接把 model設定好即可
這裡一樣可以自己設定要去抓的Template以及傳到html的object名稱
沒設定的話預設會是 account_info_detail.html
資料預設則會是object
class OrderDetailView(DetailView):
#account_info_detail.html 預設的路徑
#context_object_name = ''
model = account_info
因為沒有設置 context_object_name, 所以用 object 來呼叫我們的資料
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<h1>預約資料表</h1>
<body>
<form method="POST">
<li>預約人姓名:{{object.account_name}} 預約時間 {{object.account_order}} </li>
</form>
</body>
</html>
接著我們就可以使用Dynamic path 將 pk 傳過去
from django.urls import path
from .views import OrderCreateView, FinishView, OrderListView, OrderDetailView
app_name = 'Order_System'
urlpatterns = [
path('', OrderCreateView.as_view() , name = 'Odrer'),
path('finish/', FinishView.as_view() , name = 'finish'),
path('orderlist/', OrderListView.as_view(), name = 'order_list'),
path('detail/<str:pk>', OrderDetailView.as_view(), name = 'orderdetail')
]
就可以看到我們可以快速客製化我們單一資料的詳細資料頁面,
當網址輸入是小明時能快速呈現小明的資料
http://127.0.0.1:8000/reserve/detail/小明
UpdateView 的用途就是用來修改已經存在的資料,和CreateView用法非常像
同時他在使用時也需要用pk 或 slug來傳送
我們一樣定義好Model 和 Fields
這裡我不想讓account_name被修改,因此我只開放了兩個欄位
除此以外若沒有在 model裡設定 get_absolute_url 的話
則需要設置一個success_url 做成功修改後的網址導向
我們一樣讓他導去 finish
這裡有遇到一個小插曲,如果今天沒有設定 template_name 的話,submit按鈕的value會和account_info_form.html 一樣而不會是我們建立的account_info_update.html裡面所設定的
class OrderUpdateView(UpdateView):
template_name = 'Django_app/account_info_update.html'
model = account_info
fields = ['account_email', 'account_order']
success_url = reverse_lazy("Order_System:finish")
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form method="POST">
{% csrf_token %}
{{form.as_p}}
<input type = "submit" value = "儲存">
</form>
</body>
</html>
同樣地,我們將pk做為傳送點
from django.urls import path
from .views import OrderCreateView, FinishView, OrderListView, OrderDetailView, OrderUpdateView
app_name = 'Order_System'
urlpatterns = [
path('', OrderCreateView.as_view() , name = 'Odrer'),
path('finish/', FinishView.as_view() , name = 'finish'),
path('orderlist/', OrderListView.as_view(), name = 'order_list'),
path('detail/<str:pk>', OrderDetailView.as_view(), name = 'orderdetail'),
path('Update/<str:pk>', OrderUpdateView.as_view(), name = 'OrderUpdate')
]
我們可以將預約日期改成 10-14 並儲存
再回到DetailView 頁面,就會看到紀錄修改成功了!
DeleteView的用途是將建立好的資料刪除,當收到request method為POST時,則將該資料刪除,若收到GET則呈現此View。
DeleteView的目的是提供一個確認的頁面,方便使用者確認刪除。
views裡面一樣要設定model
還有跳轉頁面
他和DetailView很像,若沒設置Template name的話,裡面預設的Template是 [Modelname]__confirm_delete.html
context_object_name 也可以進行設定
class OrderDeleteView(DeleteView):
model = account_info
success_url = reverse_lazy("Order_System:Odrer")
from django.urls import path
from .views import OrderCreateView, FinishView, OrderListView, OrderDetailView, OrderUpdateView, OrderDeleteView
app_name = 'Order_System'
urlpatterns = [
path('', OrderCreateView.as_view() , name = 'Odrer'),
path('finish/', FinishView.as_view() , name = 'finish'),
path('orderlist/', OrderListView.as_view(), name = 'order_list'),
path('detail/<str:pk>', OrderDetailView.as_view(), name = 'orderdetail'),
path('Update/<str:pk>', OrderUpdateView.as_view(), name = 'OrderUpdate'),
path('Delete/<str:pk>', OrderDeleteView.as_view(), name = 'OrderDelete')
]
和DetailView 一樣若沒設定context_object_name的話,預設是object
我們就可以指定pk 來做刪除
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form method="POST">
{% csrf_token %}
<h1>你確定要刪除{{object.account_name}}的資料嗎</h1>
<input type = "submit" value = "確認">
</form>
</body>
</html>
當進到這個頁面時就是準備要進行刪除
按下確認後會跳轉回預約頁面
我們再回去DetailView頁面找小明時,會發現已經找不到了!
因為要時間剩的不多,所以把兩天的內容濃縮成一天,因為專注在新內容就沒有太多時間檢查,如果有問題的話可以再跟我說喔!
那我們就明天見了~
https://docs.djangoproject.com/en/4.1/topics/class-based-views/intro/
https://www.learncodewithmike.com/2020/04/django-class-based-views.html
https://andyludeveloper.medium.com/%E7%8E%A9-django-part-5-generic-view-62f3a6c018cd